#include<QFile>
#include<QString>
#include<QTextStream>
#include<QCalendarWidget>
#include<QTableWidget>
#include<QLabel>
#include<QLayout>
#include<QDateTimeEdit>
#include<QComboBox>
#include<QTextEdit>
#include<QLineEdit>
#include<fstream>
#include<QPainter>
#include<QTextCharFormat>

using namespace std;

#include "calendar.h"

Calendar::Calendar(QWidget *parent) : QWidget(parent)
{
	calendarWidget=new QCalendarWidget(this);
	tableWidget=new QTableWidget(this);

	//bold character format
	bold.setFontWeight(QFont::Bold);

	weekendFormat=calendarWidget->dateTextFormat(QDate(2009, 1, 4));
	weekendFormat=calendarWidget->dateTextFormat(QDate(2009, 1, 5));

	date=new QLabel;

	//dump the contents of the event file into the 'events' vector
	//open the file stream for reading/writing text
	QFile eventsFile(".events");
	eventsFile.open(QIODevice::ReadWrite | QIODevice::Text);

	QTextStream stream(&eventsFile);
	//read while the end of the stream hasn't been reached
	while(!stream.atEnd())
	{
		Events w;

		w.title=new QTableWidgetItem(stream.readLine());
		w.location=new QTableWidgetItem(stream.readLine());
		w.description=new QTableWidgetItem(stream.readLine());		

		w.begin=new QDateTimeEdit;
		w.begin->setDateTime(w.begin->dateTime().fromString(stream.readLine(), "MMddyyyy HHmm ap"));

		w.end=new QDateTimeEdit;
		w.end->setDateTime(w.end->dateTime().fromString(stream.readLine(), "MMddyyyy HHmm ap"));

		w.recurrence=new QComboBox;
		w.recurrence->addItem("None");
		w.recurrence->addItem("Daily");
		w.recurrence->addItem("Weekly");
		w.recurrence->addItem("Monthly");
		w.recurrence->addItem("Yearly");
		w.recurrence->setCurrentIndex(w.recurrence->findText(stream.readLine()));

		widgets.push_back(w);	//populate the vector
	}
	//end dump

	//load the settings
	fstream settings;
	settings.open(".settings", ios_base::in);
	bool s;
	settings>>s;
	showCalendarGrid(s);
	settings>>s;
	showWeekNumbers(s);
	settings>>s;
	showTableGrid(s);
	//settings loaded

	//set up UI
	tableWidget->setColumnCount(6);
	tableWidget->setRowCount(0);
	tableWidget->setAlternatingRowColors(true);
	tableWidget->setColumnWidth(3, 150);
	tableWidget->setColumnWidth(4, 150);
	tableWidget->setColumnWidth(5, 75);

	QStringList hHeader;
	hHeader<<"Title"<<"Location"<<"Description"
		   <<"Begin"<<"End"<<"Recurrence";
	tableWidget->setHorizontalHeaderLabels(hHeader);

	connectSignalsSlots();

	QVBoxLayout *mainLayout=new QVBoxLayout;
	mainLayout->addWidget(calendarWidget);
	mainLayout->addWidget(date);
	mainLayout->addWidget(tableWidget);

	setLayout(mainLayout);
	updateCalendar(calendarWidget->selectedDate().year(), calendarWidget->selectedDate().month());
	updateTable(calendarWidget->selectedDate());
	//end set up UI
}

Calendar::~Calendar()
{
	saveChangesMade();
	saveToDisk();
}

void Calendar::connectSignalsSlots()
{
	connect(calendarWidget, SIGNAL(clicked(QDate)),
			this, SLOT(updateTable(QDate)));

	connect(calendarWidget, SIGNAL(currentPageChanged(int,int)),
			this, SLOT(updateCalendar(int,int)));

	connect(calendarWidget, SIGNAL(currentPageChanged(int,int)),
			this, SLOT(setSelectedDate(int,int)));
}

void Calendar::updateTable(QDate selectedDate)
{
	saveChangesMade();
	updateCalendar(selectedDate.year(), selectedDate.month());
	tableWidget->setRowCount(0);

	//populate the table
	date->setText(/*sdate*/selectedDate.toString("MMM d, yyyy"));
	for(int i=0; i<widgets.size(); i++)
	{
		//check if the event is happening that day,
		switch(widgets[i].recurrence->currentIndex())
		{
		case 0:
			forNoneTable(i);
			break;
		case 1:
			forDailyTable(i);
			break;
		case 2:
			forWeeklyTable(i);
			break;
		case 3:
			forMonthlyTable(i);
			break;
		case 4:
			forYearlyTable(i);
			break;
		};
	}
	//end populate the table
}

void Calendar::forNoneTable(int index)
{
	if(widgets[index].begin->date().toString("MMM d, yyyy")==
	   calendarWidget->selectedDate().toString("MMM d, yyyy"))
	{
		post(index);			//the event is happening on this day, post it
	}
}

void Calendar::forDailyTable(int index)
{
	if(calendarWidget->selectedDate()>=widgets[index].begin->date() &&
	   calendarWidget->selectedDate()<=widgets[index].end->date())
	{
		post(index);			//the event is happening on this day, post it
	}
}

void Calendar::forWeeklyTable(int index)
{
	if(calendarWidget->selectedDate().dayOfWeek()==
	   widgets[index].begin->date().dayOfWeek())
	{
		if(calendarWidget->selectedDate()>=widgets[index].begin->date() &&
		   calendarWidget->selectedDate()<=widgets[index].end->date())
		{
			post(index);		//the event is happening on this day, post it
		}
	}
}

void Calendar::forMonthlyTable(int index)
{
	if(calendarWidget->selectedDate().day()==
	   widgets[index].begin->date().day())
	{
		if(calendarWidget->selectedDate()>=widgets[index].begin->date() &&
		   calendarWidget->selectedDate()<=widgets[index].end->date())
		{
			post(index);		//the event is happening on this day, post it
		}
	}
}

void Calendar::forYearlyTable(int index)
{
	if(calendarWidget->selectedDate().month()==widgets[index].begin->date().month() &&
	   calendarWidget->selectedDate().day()==widgets[index].begin->date().day())
	{
		if(calendarWidget->selectedDate()>=widgets[index].begin->date() &&
		   calendarWidget->selectedDate()<=widgets[index].end->date())
		{
			post(index);		//the event is happening on this day, post it
		}
	}
}

void Calendar::post(int index)
{
	int r=tableWidget->rowCount();
	tableWidget->setRowCount(tableWidget->rowCount()+1);

	tableWidget->setItem(r, 0, widgets[index].title);
	tableWidget->setItem(r, 1, widgets[index].location);
	tableWidget->setItem(r, 2, widgets[index].description);

	QDateTimeEdit *bte=new QDateTimeEdit(widgets[index].begin->dateTime());
	tableWidget->setCellWidget(r, 3, bte);	//bte - begin time edit

	QDateTimeEdit *ete=new QDateTimeEdit(widgets[index].end->dateTime());
	tableWidget->setCellWidget(r, 4, ete);	//ete - end time edit

	QComboBox *tmp=new QComboBox;
	tmp->addItem("None");
	tmp->addItem("Daily");
	tmp->addItem("Weekly");
	tmp->addItem("Monthly");
	tmp->addItem("Yearly");

	tmp->setCurrentIndex(widgets[index].recurrence->currentIndex());

	tableWidget->setCellWidget(r, 5, tmp);
}

void Calendar::addEvent()
{
	Events w;
	w.location=new QTableWidgetItem;
	w.title=new QTableWidgetItem;
	w.description=new QTableWidgetItem;

	w.begin=new QDateTimeEdit(calendarWidget->selectedDate());
	w.end=new QDateTimeEdit(calendarWidget->selectedDate());

	w.recurrence=new QComboBox;
	w.recurrence->addItem("None");
	w.recurrence->addItem("Daily");
	w.recurrence->addItem("Weekly");
	w.recurrence->addItem("Monthly");
	w.recurrence->addItem("Yearly");
	w.recurrence->setCurrentIndex(0);

	//increment the table's row count
	tableWidget->setRowCount(tableWidget->rowCount()+1);

	int r=tableWidget->rowCount()-1;
	tableWidget->setItem(r, 0, w.title);
	tableWidget->setItem(r, 1, w.location);
	tableWidget->setItem(r, 2, w.description);

	tableWidget->setCellWidget(r, 3, new QDateTimeEdit(w.begin->dateTime()));
	tableWidget->setCellWidget(r, 4, new QDateTimeEdit(w.end->dateTime()));

	QComboBox *tmp=new QComboBox;
	tmp->addItem("None");
	tmp->addItem("Daily");
	tmp->addItem("Weekly");
	tmp->addItem("Monthly");
	tmp->addItem("Yearly");
	tmp->setCurrentIndex(w.recurrence->currentIndex());
	tableWidget->setCellWidget(r, 5, tmp);

	widgets.push_back(w);

	updateTable(calendarWidget->selectedDate());
}

void Calendar::deleteEvent()
{
	if(tableWidget->rowCount()==0)
		return;

	int cr=tableWidget->currentRow();
	for(int i=0; i<widgets.size(); i++)
	{
		if(widgets[i].title==tableWidget->item(cr, 0))
		{
			tableWidget->removeRow(cr);
			widgets.remove(i);	//remove this widget from memory so it
		}						//won't be written to the file stream on save()

	}
}

void Calendar::saveToDisk()
{
	fstream stream(".events", ios_base::out);
	for(int i=0; i<widgets.size(); i++)
	{
		//dump the widgets vector into the .events file
		stream<<widgets[i].title->text().toStdString()<<endl;
		stream<<widgets[i].location->text().toStdString()<<endl;
		stream<<widgets[i].description->text().toStdString()<<endl;
		stream<<widgets[i].begin->dateTime().toString("MMddyyyy HHmm ap").toStdString()<<endl;
		stream<<widgets[i].end->dateTime().toString("MMddyyyy HHmm ap").toStdString()<<endl;;
		stream<<widgets[i].recurrence->currentText().toStdString()<<endl;
		//widget[i] is now saved to disk
	}
	//done saving to disk
}

void Calendar::updateCalendar(int year, int month)
{
	//clear the text format for the calendar month that was choosen

	//check if a year and month have already been assigned
	//if not, assign it the selected year and month
	if(year==-1)
		year=calendarWidget->selectedDate().year();

	if(month==-1)
		month=calendarWidget->selectedDate().month();

	QDate tmp(year, month, 1);	//initialize tmp to the first day of the month

	//iterate while we're still in the same month
	while(month==tmp.month())
	{
		if(eventCount(tmp)==0)
		{
			//no events occur, set formatting
			if(tmp.dayOfWeek()>5)
				//if it's a weekend, set weekend formatting
				calendarWidget->setDateTextFormat(tmp, weekendFormat);
			else
				//it's a weekday, set weekday formatting
				calendarWidget->setDateTextFormat(tmp, weekdayFormat);
		}
		else
			//an event occurs this date, bold it
			calendarWidget->setDateTextFormat(tmp, bold);

		tmp=tmp.addDays(1);		//continue to the next day
	}
}

void Calendar::saveChangesMade()
{
	//store the data that was edited
	for(int i=0; i<tableWidget->rowCount(); i++)
	{
		//for every widget
		for(int j=0; j<widgets.size(); j++)
		{
			//check if widget[i].title corresponds
			//to the one displayed on the table
			if(widgets[j].title==tableWidget->item(i, 0))
			{
				//it does, save the changes made
				tableWidget->takeItem(i, 0);
				tableWidget->takeItem(i, 1);
				tableWidget->takeItem(i, 2);
				widgets[j].begin->setDateTime(((QDateTimeEdit*)tableWidget->cellWidget(i, 3))->dateTime());
				widgets[j].end->setDateTime(((QDateTimeEdit*)tableWidget->cellWidget(i, 4))->dateTime());
				widgets[j].recurrence->setCurrentIndex(((QComboBox*)tableWidget->cellWidget(i, 5))->currentIndex());
			}
		}
	}
	//the data that was edited is now saved in memory
}

int Calendar::eventCount(QDate date)
{
	saveChangesMade();
	int count=0;

	//for every widget
	for(int i=0; i<widgets.size(); i++)
	{
		//check if it is occuring on that date
		//if it is, increment the count
		switch(widgets[i].recurrence->currentIndex())
		{
		case 0:
			if(widgets[i].begin->date()==date)
				count++;
			break;
		case 1:
			if(date>=widgets[i].begin->date() &&
			   date<=widgets[i].end->date())
				count++;
		case 2:
			if(date.dayOfWeek()==widgets[i].begin->date().dayOfWeek())
				if(date>=widgets[i].begin->date() &&
				   date<=widgets[i].end->date())
					count++;
		case 3:
			if(date.day()==widgets[i].begin->date().day())
				if(date>=widgets[i].begin->date() &&
				   date<=widgets[i].end->date())
					count++;
			break;
		case 4:
			if(date.month()==widgets[i].begin->date().month() &&
			   date.day()==widgets[i].begin->date().day())
				if(date>=widgets[i].begin->date() &&
				   date<=widgets[i].end->date())
					count++;
			break;
		}
	}
	return count;
}

void Calendar::showCalendarGrid(bool show)
{
	//set the calendar grid visible or not visible
	calendarWidget->setGridVisible(show);
}

void Calendar::showWeekNumbers(bool show)
{
	//set the calendars vertical header to visible or not visible
	calendarWidget->setVerticalHeaderFormat((QCalendarWidget::VerticalHeaderFormat)show);
}

void Calendar::showTableGrid(bool show)
{
	//set the tables grid to visible or not visible
	tableWidget->setShowGrid(show);
}

void Calendar::setSelectedDate(int year, int month)
{
	//quick fix to a display bug on the tableWidget
	calendarWidget->setSelectedDate(QDate(year, month, 1));
	updateTable(calendarWidget->selectedDate());
}
